package com.adcc.ags.cgw.resources;

import com.adcc.ags.cgw.App;
import com.adcc.ags.cgw.configuration.BlackListFactory;
import com.adcc.ags.cgw.configuration.UserListFactory;
import com.adcc.ags.cgw.entity.user.*;
import com.adcc.ags.cgw.proxy.UserProxy;
import com.adcc.ags.cgw.utils.Constant;
import com.adcc.ags.cgw.vo.ResultState;
import com.adcc.ags.cgw.vo.ResultVO;
import com.adcc.utility.codec.MD5;
import com.adcc.utility.log.Log;
import com.adcc.utility.xml.ADCCXML;
import com.adcc.utility.xml.ADCCXMLFactory;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Optional;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
import org.glassfish.jersey.media.multipart.FormDataMultiPart;
import org.glassfish.jersey.media.multipart.FormDataParam;
import org.glassfish.jersey.media.multipart.file.FileDataBodyPart;

import javax.ws.rs.*;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Map;

/**
 * 网关用户接口
 */
@Path("/user")
@Produces("application/json;charset=UTF-8")
public class UserResource {

    /**
     * 拆解用户
     * @param json
     * @return
     */
    private Optional<User> parserUser(String json){
        try{
            User user = new User();
            Map<String,Object> map = new ObjectMapper().readValue(json,Map.class);

            // 拆解用户ID
            if(!map.containsKey("id")){
                Log.error(UserResource.class.getName(),"parse user error missing id");
                return Optional.absent();
            }
            user.setId(map.get("id").toString());

            // 拆解用户名称
            if(!map.containsKey("name")){
                Log.error(UserResource.class.getName(),"parse user error missing name");
                return Optional.absent();
            }
            user.setName(map.get("name").toString());

            // 拆解报文类型
            if(!map.containsKey("msgType")){
                Log.error(UserResource.class.getName(),"parse user error missing msgType");
                return Optional.absent();
            }
            int msgType = Integer.valueOf(map.get("msgType").toString());
            if(msgType == MsgType.SplitResult.ordinal()){
                user.setMsgType(MsgType.SplitResult);
            }else{
                user.setMsgType(MsgType.RawMsg);
            }

            // 拆解下行转发
            if(!map.containsKey("downlinkForword")){
                Log.error(UserResource.class.getName(),"parse user error missing downlinkForword");
                return Optional.absent();
            }
            user.setDownlinkForward(Boolean.valueOf(map.get("downlinkForword").toString()));

            // 拆解发送队列
            if(!map.containsKey("sendQueue")){
                Log.error(UserResource.class.getName(),"parse user error missing sendQueue");
                return Optional.absent();
            }
            user.setSendQueue(map.get("sendQueue").toString());

            // 拆解接收队列
            if(!map.containsKey("recvQueue")){
                Log.error(UserResource.class.getName(),"parse user error missing recvQueue");
                return Optional.absent();
            }
            user.setRecvQueue(map.get("recvQueue").toString());

            // 拆解路由信息
            if(map.containsKey("routes")){
                List<Map<String,Object>> list = (List<Map<String,Object>>)map.get("routes");
                Optional<List<Route>> optional = parserRoute(list);
                if(optional.isPresent()){
                    user.setRouteList(optional.get());
                }else{
                    return Optional.absent();
                }
            }
            return Optional.of(user);
        }catch (Exception ex){
            Log.error(UserResource.class.getName(),"parserUser() error",ex);
            return Optional.absent();
        }
    }

    /**
     * 拆解路由
     * @param list
     * @return
     */
    private Optional<List<Route>> parserRoute(List<Map<String,Object>> list){
        try{
            List<Route> routes = Lists.newArrayListWithExpectedSize(100);
            for(Map<String,Object> map : list){
                Route route = null;

                // 解析路由类型
                if(!map.containsKey("type")){
                    Log.error(UserResource.class.getName(),"parse user error missing type");
                }
                int type = Integer.parseInt(map.get("type").toString());
                if(type == 0){
                    route = new DownlinkRoute();
                    route.setType(RouteType.Downlink);
                }else if(type == 1){
                    route = new UplinkRoute();
                    route.setType(RouteType.Uplink);
                }else{
                    route = new GroundRoute();
                    route.setType(RouteType.Ground);
                }

                // 解析路由ID
                if(!map.containsKey("id")){
                    Log.error(UserResource.class.getName(),"parse user error missing id");
                }
                route.setId(map.get("id").toString());

                // 解析路由名称
                if(!map.containsKey("name")){
                    Log.error(UserResource.class.getName(),"parse user error missing name");
                }
                route.setName(map.get("name").toString());

                // 解析路由条件
                if(route.getType() == RouteType.Downlink){
                    if(map.containsKey("sendAddress")){
                        String addresses = map.get("sendAddress").toString();
                        ((DownlinkRoute) route).setSendAddress(addresses);
                    }
                    if(map.containsKey("recvAddress")){
                        String[] addresses = map.get("recvAddress").toString().split(",");
                        ((DownlinkRoute) route).setRecvAddress(addresses);
                    }
                    if(map.containsKey("smi")){
                        String[] smi = map.get("smi").toString().split(",");
                        ((DownlinkRoute) route).setSmi(smi);
                    }
                    if(map.containsKey("an")){
                        String[] an = map.get("an").toString().split(",");
                        ((DownlinkRoute) route).setAn(an);
                    }
                    if(map.containsKey("fi")){
                        String[] fi = map.get("fi").toString().split(",");
                        ((DownlinkRoute) route).setFi(fi);
                    }
                    if(map.containsKey("rgs")){
                        String[] rgs = map.get("rgs").toString().split(",");
                        ((DownlinkRoute) route).setRgs(rgs);
                    }
                    if(map.containsKey("specLabel") && map.containsKey("specIndex")){
                        SpecLabel specLabel = new SpecLabel();
                        specLabel.setIndex(Integer.parseInt(map.get("specIndex").toString()));
                        specLabel.setContent(map.get("specLabel").toString());
                        ((DownlinkRoute) route).setSpecLabel(specLabel);
                    }
                }
                if(route.getType() == RouteType.Uplink){
                    if(map.containsKey("sendAddress")){
                        String addresses = map.get("sendAddress").toString();
                        ((UplinkRoute) route).setSendAddress(addresses);
                    }
                    if(map.containsKey("recvAddress")){
                        String[] addresses = map.get("recvAddress").toString().split(",");
                        ((UplinkRoute) route).setRecvAddress(addresses);
                    }
                    if(map.containsKey("smi")){
                        String[] smi = map.get("smi").toString().split(",");
                        ((UplinkRoute) route).setSmi(smi);
                    }
                    if(map.containsKey("an")){
                        String[] an = map.get("an").toString().split(",");
                        ((UplinkRoute) route).setAn(an);
                    }
                    if(map.containsKey("specLabel") && map.containsKey("specIndex")){
                        SpecLabel specLabel = new SpecLabel();
                        specLabel.setIndex(Integer.parseInt(map.get("specIndex").toString()));
                        specLabel.setContent(map.get("specLabel").toString());
                        ((UplinkRoute) route).setSpecLabel(specLabel);
                    }
                    if(map.containsKey("destination")){
                        String[] destination = map.get("destination").toString().split(",");
                        ((UplinkRoute) route).setDestination(destination);
                    }
                }else{
                    if(map.containsKey("specLabel") && map.containsKey("specIndex")){
                        SpecLabel specLabel = new SpecLabel();
                        specLabel.setIndex(Integer.parseInt(map.get("specIndex").toString()));
                        specLabel.setContent(map.get("specLabel").toString());
                        ((GroundRoute)route).setSpecLabel(specLabel);
                    }
                    if(map.containsKey("destination")){
                        String[] destination = map.get("destination").toString().split(",");
                        ((GroundRoute)route).setDestination(destination);
                    }
                }
                routes.add(route);
            }
            return Optional.of(routes);
        }catch (Exception ex){
            Log.error(UserResource.class.getName(),"parserUser() error",ex);
            return Optional.absent();
        }
    }

    /***
     * 用户上线操作
     * @param user
     * @return
     */
    @POST
    @Path("/userOnline")
    public Optional<ResultVO> userOnline(@FormParam("user")String user){
        ResultVO resultVO = new ResultVO();
        try{
            if(!Strings.isNullOrEmpty(user) && !Strings.isNullOrEmpty(user)){
                try{

                    // 解析网关用户配置信息
                    Optional<User> optional = parserUser(user);
                    if(optional.isPresent()){

                        // 网关用户列表添加用户
                        UserListFactory.getInstance().addUser(optional.get());
                        UserListFactory.getInstance().save();

                        // 网关用户代理添加用户
                        UserProxy.getInstance().addUser(optional.get());
                    }else{
                        resultVO.setResult(ResultState.FAILURE,-1,"user parameter is invalid");
                    }
                }catch (Exception ex){
                    Log.error(UserResource.class.getName(),"parse user json error",ex);
                    resultVO.setResult(ResultState.FAILURE,-1,"user parameter is invalid");
                }
            }else{
                resultVO.setResult(ResultState.FAILURE,-1,"input parameters is empty or null");
            }
            return Optional.of(resultVO);
        }catch (Exception ex){
            Log.error(UserResource.class.getName(),"userOnline() error",ex);
            resultVO.setResult(ResultState.FAILURE,-1,ex.fillInStackTrace().toString());
            return Optional.of(resultVO);
        }
    }

    /**
     * 网关用户下线
     * @param userId
     * @param userName
     * @return
     */
    @POST
    @Path("/userOffline")
    public Optional<ResultVO> userOffline(@FormParam("userId")String userId,@FormParam("userName")String userName){
        ResultVO resultVO = new ResultVO();
        try{
            if(!Strings.isNullOrEmpty(userId) && !Strings.isNullOrEmpty(userName)){

                // 网关用户列表删除用户
                UserListFactory.getInstance().deleteUser(userId,userName);
                UserListFactory.getInstance().save();

                // 网关用户代理删除用户
                UserProxy.getInstance().removeUser(userId);
            }else{
                resultVO.setResult(ResultState.FAILURE,-1,"input parameters is empty or null");
            }
            return Optional.of(resultVO);
        }catch (Exception ex){
            Log.error(UserResource.class.getName(),"userOffline() error",ex);
            resultVO.setResult(ResultState.FAILURE,-1,ex.fillInStackTrace().toString());
            return Optional.of(resultVO);
        }
    }

    /**
     * 更新网关用户列表
     * @param file
     * @param md5
     * @param disposition
     * @return
     */
    @POST
    @Path("/updateUserList")
    @Consumes("multipart/form-data")
    public Optional<ResultVO> updateUserList(@FormDataParam("file") InputStream file,@FormDataParam("MD5") String md5,@FormDataParam("file") FormDataContentDisposition disposition) {
        ResultVO resultVO = new ResultVO();
        try {

            // 判断参数是否为空
            if(file == null || Strings.isNullOrEmpty(md5) || disposition == null) {
                resultVO.setResult(ResultState.FAILURE,-1,"input parameters is empty or null");
                return Optional.of(resultVO);
            }

            // 解析网关用户列表配置文件
            ADCCXML adccxml = ADCCXMLFactory.getInstance().createADCCXML();
            adccxml.parse(file);

            // MD5校验
            if(md5.equals(MD5.getMD5(adccxml.createXMLString()))){

                // 更新网关用户列表
                UserListFactory.getInstance().load(adccxml);
                UserListFactory.getInstance().save();

                // 更新用户代理
                UserProxy.getInstance().loadUserList();
                resultVO.setResult(ResultState.SUCCESS);
            }else{
                resultVO.setResult(ResultState.FAILURE,-1,"check MD5 failed");
            }
            return Optional.of(resultVO);
        } catch (Exception ex) {
            Log.error(UserResource.class.getName(), "updateUserList error()", ex);
            resultVO.setResult(ResultState.FAILURE,-1,ex.fillInStackTrace().toString());
            return Optional.of(resultVO);
        }
    }

    /**
     * 更新黑名单列表
     * @param file
     * @param md5
     * @param disposition
     * @return
     */
    @POST
    @Path("/updateBlackList")
    @Consumes("multipart/form-data")
    public Optional<ResultVO> updateBlackList(@FormDataParam("file") InputStream file,@FormDataParam("MD5") String md5,@FormDataParam("file") FormDataContentDisposition disposition) {
        ResultVO resultVO = new ResultVO();
        try {

            // 判断参数是否为空
            if(file == null || Strings.isNullOrEmpty(md5) || disposition == null) {
                resultVO.setResult(ResultState.FAILURE,-1,"input parameters is empty or null");
                return Optional.of(resultVO);
            }

            // 解析网关用户列表配置文件
            ADCCXML adccxml = ADCCXMLFactory.getInstance().createADCCXML();
            adccxml.parse(file);

            // MD5校验
            if (md5.equals(MD5.getMD5(adccxml.createXMLString()))) {
                BlackListFactory.getInstance().load(adccxml);
                BlackListFactory.getInstance().save(adccxml);
                resultVO.setResult(ResultState.SUCCESS);
            }else{
                resultVO.setResult(ResultState.FAILURE,-1,"check MD5 failed");
            }
            return Optional.of(resultVO);
        } catch (Exception ex) {
            Log.error(UserResource.class.getName(),"updateBlackList() error",ex);
            resultVO.setResult(ResultState.FAILURE,-1,ex.fillInStackTrace().toString());
            return Optional.of(resultVO);
        }
    }

    /**
     * 取得网关用户列表
     * @param multiPart
     * @return
     */
    @POST
    @Path("/getUserList")
    @Consumes("multipart/form-data")
    @Produces("multipart/form-data")
    public Optional<FormDataMultiPart> getUserList(final FormDataMultiPart multiPart) {
        FileInputStream fis = null;
        try {

            // 加载用户列表
            String strUserListFile = App.confPath + File.separator + Constant.STRING_USERLIST_FILE;
            File file = new File(strUserListFile);

            // 检查用户列表是否存在
            if(file.exists()){
                // 计算MD5
                String strMD5 = MD5.getMD5(file);

                // 比较MD5值
                if(!strMD5.equals(multiPart.getField("MD5").getValue())){
                    multiPart.field("MD5",strMD5).getBodyParts().set(0,new FileDataBodyPart("userList",file));
                    return Optional.of(multiPart);
                }else{
                    multiPart.field("MD5", "");
                    return Optional.of(multiPart);
                }
            } else {
                multiPart.field("MD5", "");
                return Optional.of(multiPart);
            }
        } catch (Exception ex) {
            Log.error(UserResource.class.getName(),"getUserList() error",ex);
            return Optional.absent();
        }finally {
            if(fis != null){
                try {
                    fis.close();
                } catch (IOException ex) {
                    Log.error(UserResource.class.getName(),"close FileInputStream error",ex);
                }
            }
        }
    }

    /**
     * 取得黑名单列表
     * @param multiPart
     * @return
     */
    @POST
    @Path("/getBlackList")
    @Consumes("multipart/form-data")
    @Produces("multipart/form-data")
    public Optional<FormDataMultiPart> getBlackList(final FormDataMultiPart multiPart) {
        FileInputStream fis = null;
        try {

            // 加载黑名单
            String strBlackListFile = App.confPath + File.separator + Constant.STRING_BLACKLIST_FILE;
            File file = new File(strBlackListFile);

            // 检查用户列表是否存在
            if(file.exists()) {
                // 计算MD5
                String strMD5 = MD5.getMD5(file);

                // 比较MD5值
                if (!strMD5.equals(multiPart.getField("MD5").getValue())) {
                    multiPart.field("MD5",strMD5).getBodyParts().set(0, new FileDataBodyPart("blackList",file));
                    return Optional.of(multiPart);
                } else {
                    multiPart.field("MD5", "");
                    return Optional.of(multiPart);
                }
            } else {
                multiPart.field("MD5", "");
                return Optional.of(multiPart);
            }
        } catch (Exception ex) {
            Log.error(UserResource.class.getName(), "getBlackList() error", ex);
            return Optional.absent();
        } finally {
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException ex) {
                    Log.error(UserResource.class.getName(), "close FileInputStream error", ex);
                }
            }
        }
    }
}
